/**
 * 
 */
package org.youisoft.summer.evaluator.unit;
import java.util.Stack;
import org.youisoft.summer.evaluator.InvokeException;
import org.youisoft.summer.evaluator.context.CalContext;
import org.youisoft.summer.evaluator.operator.Operator;
import org.youisoft.summer.evaluator.operator.base.OperateOperator;
import org.youisoft.summer.evaluator.util.Ulitity;

/**
 * @author zijiang.jl
 *
 */
public abstract class AbstractCommonUnit<R,P> extends AbstractUnit<R,P>{
	private java.lang.ThreadLocal<Stack<Operator<?>>> localStack=new java.lang.ThreadLocal<Stack<Operator<?>>>();
	private java.lang.ThreadLocal<java.util.List<Operator<?>>> localOperator=new java.lang.ThreadLocal<java.util.List<Operator<?>>>();
	private java.util.List<java.util.List<Operator<?>>> list=new java.util.ArrayList<java.util.List<Operator<?>>>();
	
	@Override
	public void init() {
		super.init();
		String[] expression=this.getExpression();
		for(String exp:expression){
			list.add(Ulitity.toBoland(Ulitity.toMiddleList(exp)));
		}
		
	}
	
	@Override
	public void reInit() {
		this.list=null;
		this.init();
		
	}
	
	private void checkLocal(){
		if(localStack.get()==null){
			localStack.set(new Stack<Operator<?>>());
		}
		if(localOperator.get()==null){
			localOperator.set(new java.util.ArrayList<Operator<?>>());
		}
		localStack.get().clear();
		localOperator.get().clear();
	}
	
	protected <C> Operator<?>[] caculateExpression(CalContext<C,R,P> context) throws InvokeException{
		for(int i=0;i<list.size();i++){
			java.util.List<Operator<?>> li=list.get(i);
			checkLocal();
			for(Operator<?> op:li){
				if(op instanceof OperateOperator){
					OperateOperator oo=(OperateOperator)op;
					Operator<?>[] param=new Operator<?>[oo.value().getOpers()];
					for(int j=oo.value().getOpers()-1;j>=0;j--){
						param[j]=localStack.get().pop();
					}
					localStack.get().push(this.callFunctionIfNessary(context, oo.value().name(),this.getUnitType(), param));
				}else{
					localStack.get().push(this.convertPlaceHolder(context,op));
				}
			}
			
			if(!localStack.get().isEmpty()){
				Operator<?> o=localStack.get().pop();
				localOperator.get().add(o);
			}else{
				localOperator.get().add(Operator.nullInstance);
			}
		}
		
		return localOperator.get().toArray(new Operator<?>[localOperator.get().size()]);
	}
	
	
	@Override
	public <C> Operator<?> doCalculate(CalContext<C,R,P> context,Operator<?> operator) throws InvokeException{
		return this.callFunctionIfNessary(context,operator,this.getfName(),this.getUnitType(),this.caculateExpression(context));
	}

}
